import { logger } from '../../types/constants'

interface EventListenerInfo {
  type: keyof HTMLElementEventMap | string
  handler: (this: Element, ev: Event) => any
}

export interface DataAttrsItem {
  type: 'data' | 'attr'
  name: string
}

/**
 * 事件绑定配置类型
 */
export interface EventBindingConfig {
  /** 是否启用 */
  enabled?: boolean | ((...args: any[]) => boolean)
  /** 主元素选择器 */
  selector: string | JQueryElement
  /** 子元素选择器 (用于事件委托) */
  childSelector?: string
  /** 事件类型 */
  eventType: keyof HTMLElementEventMap | string
  /** 事件处理器 */
  handler: (e: Event) => void
  /** 自定义跟踪元数据 */
  meta?: Record<string, any>
}

/**
 * 销毁基础类
 * 提供标准化的资源清理流程和生命周期管理
 */
export abstract class BaseDestructible {
  protected isInitialized: boolean = false
  protected abstract readonly name: string

  // 性能优化：使用 WeakMap 替代 Map，可自动释放无效引用、不会阻止垃圾回收、内存管理更安全
  // 用于支持遍历
  private eventListenerTracker: Set<Element> = new Set()
  private dataAttrsTracker: Set<Element> = new Set()
  private addedClassesTracker: Set<Element> = new Set()
  private creationTracker: Set<JQuery<HTMLElement>> = new Set()
  // 提供外部访问的跟踪器
  tracker: any = {
    eventListeners: this.trackEventListener.bind(this),
    dataAttrs: this.trackDataAttribute.bind(this),
    addedClasses: this.trackAddedClass.bind(this),
    creation: this.trackCreatedElement.bind(this),
  }

  // 存储事件监听器引用
  protected eventListeners: WeakMap<Element, EventListenerInfo[]> = new WeakMap()
  // 存储定时器引用
  protected timers: Set<number> = new Set()
  // 存储观察器引用
  protected observers: Set<MutationObserver> = new Set()
  // 存储已添加的CSS类名（同一元素支持多个类名）
  protected addedClasses: WeakMap<Element, string[]> = new WeakMap()
  // 存储使用的数据属（同一元素支持多个数据属性）
  protected readonly addedDataAttrs: WeakMap<Element, DataAttrsItem[]> = new WeakMap()
  // 存储已创建的 DOM 元素引用
  protected createdElements: WeakMap<Element, JQuery<HTMLElement>> = new WeakMap()

  /**
   * 事件绑定配置
   */
  get eventConfigs(): EventBindingConfig[] {
    return []
  }

  /**
   * 标准销毁流程（模板方法）
   */
  destroy(): Promise<void> | void {
    if (!this.isInitialized)
      return

    try {
      this.beforeDestroy()
      this.executeDestructionPipeline()
      this.onDestroy()
      this.afterDestroy()

      logger.info(`[${this.name}] Destruction completed successfully`)
    }
    catch (error: any) {
      logger.error(`[${this.name}] Destruction failed:`, error)
    }
    finally {
      this.eventListenerTracker.clear()
      this.dataAttrsTracker.clear()
      this.addedClassesTracker.clear()
      this.creationTracker.clear()
      this.isInitialized = false
    }
  }

  private static readonly DESTRUCTION_STEPS: Array<{
    name: string
    action: string
    reason?: string
    critical?: boolean
  }> = [
    // 第一阶段：清理动态行为（防止后续清理过程中触发事件）
    { name: 'EventListeners', action: 'cleanupEventListeners', reason: '优先移除事件监听器，避免在 DOM 清理过程中触发意外事件' },
    { name: 'Timers', action: 'cleanupTimers', reason: '清除定时器，防止在 DOM 移除后继续执行回调' },
    { name: 'Observers', action: 'cleanupObservers', reason: '移除观察者，避免在 DOM 变化时触发观察回调' },

    // 第二阶段：DOM 清理（必须按依赖顺序执行）
    { name: 'CreatedElements', action: 'cleanupCreatedElements', reason: '先移除自定义创建的 DOM 元素，这些元素可能包含样式和属性' },
    { name: 'CSSClasses', action: 'cleanupAddedClasses', reason: '在移除元素后清理 CSS 类，避免类名残留影响其他元素' },
    { name: 'DataAttributes', action: 'cleanupDataAttributes', reason: '清理数据属性，这些属性可能依赖于元素的存在' },
    { name: 'Styles', action: 'cleanupStyles', reason: '最后清理样式，确保所有样式相关的元素和类都已处理' },

    // 第三阶段：清理引用和状态
    { name: 'References', action: 'cleanupReferences', reason: '清理JavaScript对象引用，释放内存' },
    { name: 'Others', action: 'cleanupOthers', reason: '清理其他资源（如缓存、存储等）' },
    { name: 'StateRestoration', action: 'restoreOriginalState', critical: true, reason: '最后恢复原始状态，确保页面回到模块加载前的状态' },
  ]

  /**
   * 执行标准销毁流水线
   */
  private executeDestructionPipeline(): void {
    const beforeStats = this.getResourceStats()
    logger.debug(`[${this.name}] Before cleanup stats:`, beforeStats)

    BaseDestructible.DESTRUCTION_STEPS.forEach(({ name, action, critical }) => {
      try {
        switch (action) {
          case 'cleanupEventListeners': {
            this.cleanupEventListeners()
            break
          }
          case 'cleanupTimers': {
            this.cleanupTimers()
            break
          }
          case 'cleanupObservers': {
            this.cleanupObservers()
            break
          }
          case 'cleanupAddedClasses': {
            this.cleanupAddedClasses()
            break
          }
          case 'cleanupDataAttributes': {
            this.cleanupDataAttributes()
            break
          }
          case 'cleanupStyles': {
            this.cleanupStyles()
            break
          }
          case 'cleanupCreatedElements': {
            this.cleanupCreatedElements()
            break
          }
          case 'cleanupReferences': {
            this.cleanupReferences()
            break
          }
          case 'cleanupOthers': {
            this.cleanupOthers()
            break
          }
          case 'restoreOriginalState': {
            this.restoreOriginalState()
            break
          }
          default:
            throw new Error(`Unknown cleanup action: ${action}`)
        }
        logger.debug(`[${this.name}] ${name} cleaned up`)
      }
      catch (error: any) {
        const message = `[${this.name}] ${name} cleanup failed`
        critical ? logger.error(message, error) : logger.warn(message, error)
        if (critical)
          throw error
      }
    })

    const afterStats = this.getResourceStats()
    logger.debug(`[${this.name}] After cleanup stats:`, afterStats)
  }

  // ============================= 基础方法 =============================
  /**
   * 自动绑定事件
   */
  protected autoBindEvents(immediatePrint: boolean = false): void {
    this.bindEventsWithConfig(this.eventConfigs)

    if (immediatePrint)
      this.printResourceStats()
  }

  /**
   * 批量绑定事件并自动跟踪
   */
  protected bindEventsWithConfig(configs: EventBindingConfig[]): void {
    configs.forEach((config) => {
      const { enabled, selector, childSelector, eventType, handler, meta } = config

      const selectorSource = typeof selector === 'string' ? selector : 'jQueryObject'
      const eventMeta = {
        selector: selectorSource,
        eventType: config.eventType,
        childSelector,
      }

      // 检查启用状态
      const isEnabled = typeof enabled === 'function'
        ? enabled(this)
        : enabled ?? true

      if (!isEnabled) {
        logger.debug(`[${this.name}] 事件绑定已禁用`, eventMeta)
        return
      }

      // 获取目标元素
      const $base = typeof selector === 'string'
        ? $(selector)
        : selector

      if (!$base || !$base.length) {
        logger.warn(`[${this.name}] 目标元素未找到，跳过事件绑定`, eventMeta)
        return
      }

      try {
        // 绑定事件
        const $target = childSelector
          ? $base.on(eventType, childSelector, handler as unknown as JQuery.EventHandler<HTMLElement>)
          : $base.on(eventType, handler as unknown as JQuery.EventHandler<HTMLElement>)

        // 跟踪监听器 (使用原生DOM元素)
        if ($target.length > 0) {
          this.tracker.eventListeners(
            $target,
            eventType,
            handler,
            { ...meta, ...eventMeta },
          )
        }
      }
      catch (error) {
        logger.warn(`[${this.name}] 事件绑定失败`, {
          config: JSON.stringify(config),
          error: error instanceof Error ? error.message : String(error),
        })
      }
    })
  }

  // ============================= 可覆盖的方法 =============================
  /**
   * 自定义销毁逻辑
   */
  protected beforeDestroy(): Promise<void> | void {}
  protected afterDestroy(): Promise<void> | void {}
  protected onDestroy(): Promise<void> | void {}

  /**
   * 恢复原始状态
   */
  protected restoreOriginalState(): void {}

  // ============================= 记录方法 =============================
  /**
   * 跟踪事件监听器（使用jQuery元素），支持处理同一元素不同事件类型的添加
   * @param $element jQuery元素
   * @param type 事件类型
   * @param handler 事件处理器
   * @param meta 元数据（可选）
   */
  private trackEventListener($element: JQuery<HTMLElement>, type: string, handler: EventListener, meta?: Record<string, any>): void {
    if (!$element || !$element.length)
      return

    const element = $element[0]

    // 获取或初始化监听器数组
    const listeners = this.eventListeners.get(element) || []

    // 检查是否已存在相同监听器
    const exists = listeners.some(
      l => l.type === type && l.handler === handler,
    )

    if (!exists) {
      listeners.push({ type, handler })
      this.eventListeners.set(element, listeners)
      this.eventListenerTracker.add(element)

      logger.debug(`[${this.name}] 跟踪事件: ${type}`, {
        element,
        ...meta,
      })
    }
  }

  /**
   * 跟踪数据属性（使用jQuery元素）
   * @param $element jQuery元素
   * @param type 属性类型（data或attr）
   * @param name 属性名
   */
  private trackDataAttribute($element: JQuery<HTMLElement>, type: 'data' | 'attr', name: string): void {
    if (!$element || !$element.length)
      return

    const element = $element[0]
    const currentAttrs = this.addedDataAttrs.get(element) || []

    // 避免重复添加相同属性
    if (!currentAttrs.some(attr => attr.type === type && attr.name === name)) {
      this.addedDataAttrs.set(element, [...currentAttrs, { type, name }])
    }

    this.dataAttrsTracker.add($element[0])
  }

  /**
   * 跟踪添加的类（使用jQuery元素）
   * @param $element jQuery元素
   * @param classNames 类名列表
   */
  private trackAddedClass($element: JQuery<HTMLElement>, classNames: string): void {
    if (!$element || !$element.length)
      return

    const element = $element[0]
    const currentClasses = this.addedClasses.get(element) || []

    // 分割类名并去重
    const newClasses = classNames.split(/\s+/).filter(Boolean)
    const uniqueClasses = [...new Set([...currentClasses, ...newClasses])]

    if (uniqueClasses.length > currentClasses.length) {
      this.addedClasses.set(element, uniqueClasses)
    }

    this.addedClassesTracker.add(element)
  }

  /**
   * 跟踪创建的元素（使用jQuery元素）
   * @param $element jQuery元素
   */
  private trackCreatedElement($element: JQuery<HTMLElement>): void {
    if (!$element || !$element.length)
      return

    this.createdElements.set($element[0], $element)
    this.creationTracker.add($element)
  }

  // ============================= 清理方法 =============================
  // 清理所有监听器
  cleanupEventListeners(): void {
    try {
      this.handleCleanupEventListeners()
      logger.debug(`[${this.name}] Event listeners cleaned`)
    }
    catch (error) {
      logger.warn(`[${this.name}] Event listener cleanup failed:`, error)
    }
  }

  // 清理所有定时器
  cleanupTimers(): void {
    try {
      this.handleCleanupTimers()
      logger.debug(`[${this.name}] Timers cleaned`)
    }
    catch (error) {
      logger.warn(`[${this.name}] Timer cleanup failed:`, error)
    }
  }

  // 清理所有观察器
  cleanupObservers(): void {
    try {
      this.handleCleanupObservers()
      logger.debug(`[${this.name}] Observers cleaned`)
    }
    catch (error) {
      logger.warn(`[${this.name}] Observer cleanup failed:`, error)
    }
  }

  // 清理所有添加的CSS类
  cleanupAddedClasses(): void {
    try {
      this.handleCleanupAddedClasses()
      logger.debug(`[${this.name}] CSS classes cleaned`)
    }
    catch (error) {
      logger.warn(`[${this.name}] CSS class cleanup failed:`, error)
    }
  }

  // 移除所有数据属性标记
  cleanupDataAttributes(): void {
    try {
      this.handleCleanupDataAttributes()
      logger.debug(`[${this.name}] Removed all data attributes`)
    }
    catch (error) {
      logger.warn(`[${this.name}] Failed to remove data attributes:`, error)
    }
  }

  // 清理所有样式
  cleanupStyles(): void {
    try {
      this.handleCleanupStyles()
      logger.debug(`[${this.name}] Styles cleaned`)
    }
    catch (error) {
      logger.warn(`[${this.name}] Style cleanup failed:`, error)
    }
  }

  // 清理所有创建的元素
  cleanupCreatedElements(): void {
    try {
      this.handleCleanupCreatedElements()
      logger.debug(`[${this.name}] Created elements cleaned`)
    }
    catch (error) {
      logger.warn(`[${this.name}] Element cleanup failed:`, error)
    }
  }

  // 清理所有引用
  cleanupReferences(): void {
    try {
      this.handleCleanupReferences()
      logger.debug(`[${this.name}] References cleaned`)
    }
    catch (error) {
      logger.warn(`[${this.name}] Reference cleanup failed:`, error)
    }
  }

  // 清理其他资源
  cleanupOthers(): void {
    try {
      this.handleCleanupOthers()
      logger.debug(`[${this.name}] Others cleaned`)
    }
    catch (error) {
      logger.warn(`[${this.name}] Others cleanup failed:`, error)
    }
  }

  // ============================= 可选覆盖的清理逻辑 =============================
  protected handleCleanupEventListeners(): void {
    if (this.eventListenerTracker.size === 0)
      return

    this.eventListenerTracker.forEach((element) => {
      const $element = $(element)
      const listeners = this.eventListeners.get(element)

      listeners?.forEach(({ type, handler }) => {
        try {
          $element.off(type as any, handler as any)
          logger.debug(`[${this.name}] 已移除事件监听: ${type}`, element)
        }
        catch (error) {
          logger.warn(`[${this.name}] 移除事件监听失败`, {
            type,
            element,
            error: error instanceof Error ? error.message : String(error),
          })
        }
      })
    })
    this.eventListenerTracker.clear()
  }

  protected handleCleanupTimers(): void {
    if (this.timers.size === 0)
      return

    this.timers.forEach((timerId) => {
      try {
        clearTimeout(timerId)
        clearInterval(timerId)
        logger.debug(`[${this.name}] Cleared timer: ${timerId}`)
      }
      catch (error) {
        logger.warn(`[${this.name}] Failed to clear timer: ${timerId}`, error)
      }
    })
    this.timers.clear()
    logger.info(`[${this.name}] All timers cleaned up`)
  }

  protected handleCleanupObservers(): void {
    if (this.observers.size === 0)
      return

    this.observers.forEach((observer) => {
      try {
        observer.disconnect()
        logger.debug(`[${this.name}] Disconnected observer`)
      }
      catch (error) {
        logger.warn(`[${this.name}] Failed to disconnect observer:`, error)
      }
    })
    this.observers.clear()
    logger.info(`[${this.name}] All observers cleaned up`)
  }

  protected handleCleanupAddedClasses(): void {
    if (this.addedClassesTracker.size === 0)
      return

    this.addedClassesTracker.forEach((element) => {
      try {
        const classes = this.addedClasses.get(element)
        if (classes && element.isConnected) {
          const $el = $(element)
          classes.forEach(className => $el.removeClass(className))
          logger.debug(`[${this.name}] Removed classes: ${classes.join(', ')}`)
        }
      }
      catch (error) {
        logger.warn(`[${this.name}] Failed to remove classes`, error)
      }
    })
    this.addedClassesTracker.clear()
  }

  protected handleCleanupDataAttributes(): void {
    if (this.dataAttrsTracker.size === 0)
      return

    this.dataAttrsTracker.forEach((element) => {
      try {
        const attrs = this.addedDataAttrs.get(element)
        if (attrs && element.isConnected) {
          const $el = $(element)
          attrs.forEach((attr) => {
            attr.type === 'data'
              ? $el.removeData(attr.name)
              : $el.removeAttr(attr.name)
            logger.debug(`[${this.name}] Removed ${attr.type} attribute: ${attr.name}`)
          })
        }
      }
      catch (error) {
        logger.warn(`[${this.name}] Failed to remove data attribute`, error)
      }
    })
    this.dataAttrsTracker.clear()
  }

  protected handleCleanupStyles(): void {}

  protected handleCleanupCreatedElements(): void {
    if (this.creationTracker.size === 0)
      return

    this.creationTracker.forEach(($el) => {
      try {
        $el.remove()
      }
      catch (error) {
        logger.warn(`Remove element failed`, error)
      }
    })
    this.creationTracker.clear()
  }

  protected handleCleanupReferences(): void {}

  protected handleCleanupOthers(): void {}

  // 获取当前模块的资源占用统计信息
  getResourceStats(): any {
    return {
      eventListeners: this.eventListenerTracker.size,
      timers: this.timers.size,
      observers: this.observers.size,
      dataAttributes: this.dataAttrsTracker.size,
      cssClasses: this.addedClassesTracker.size,
      createdElements: this.creationTracker.size,
    }
  }

  /**
   * 打印资源统计信息
   * @param options 配置选项
   * @param options.prefix 前缀
   * @param options.showEmpty 是否显示所有统计项（包括值为0的）
   * @param options.format 输出格式
   */
  printResourceStats(options?: {
    prefix?: string
    showEmpty?: boolean
    format?: 'table' | 'json'
  }): void {
    const stats = this.getResourceStats()
    const {
      showEmpty = false,
      format = 'json',
      prefix = '',
    } = options || {}

    // 过滤空值（当不需要显示空值时）
    const filteredStats = showEmpty
      ? stats
      : Object.fromEntries(Object.entries(stats).filter(([_, v]) => v !== 0))

    if (Object.keys(filteredStats).length === 0) {
      logger.debug(`[${this.name}] ${prefix}无活跃资源`)
      return
    }

    // 格式化输出
    if (format === 'table') {
      logger.table(`[${this.name}] ${prefix}当前资源统计情况`, filteredStats)
    }
    else {
      logger.info(`[${this.name}] ${prefix}当前资源统计情况`, filteredStats)
    }
  }
}
